Coder 灰桑

Stay Foolish, Always Foolish

揭开 SwiftUI 神秘面纱

SwiftUI 如何看你写的代码

  • identity: swiftUI 根据 ID 来识别相应的元素
  • lifetime: swiftUI 更重存在的 View 和 数据
  • dependence: swiftUI 理解什么时候什么原因去更新界面

swiftUI 根据这三个方面去决定什么时候怎样去改变什么。

identity

swiftUI 有两种不同的 identify。

  • Explicit identify(明确的):用来自定义或者数据驱动的标识。
    • 🌰1.List forEach 中使用的 id 来区分 item
    • 🌰2.ScrollViewReader 滚动到某个 ID
  • Structural identify(结构性):通过类型和在层级中的位置来区分。
    • 🌰在 UIkit 中是使用指针来确定唯一的 View。但是 swiftUI 是指类型的并没有指针去确定谁是谁,所以 swiftUI 通过视图的层级结构的位置和类型来确定当前的 View 是哪一个。(所以尽量避免使用 AnyView,会擦除 View 的类型,降低性能)

lifetime

swiftUI view 的生命周期其实就是 identify 的生命周期,一旦 identify 变更,lifetime 就相应的结束了。

state lifetime

View value

View value 是短暂的可能随时变更, View identify 是持久的。

state lifetime

State 在 view 初始化的时候就跟 View 的 identify 绑定在一起,即使之后 State 变更了,只要 identify 发生变化 State 也会被释放,产生新的 State 和 新 View 的 identify 绑定。

因此选择一个独一无二的 identify 能够避免很多奇怪的 bug 和动画。

dependence

dependence 的类型

  • @Binding
  • @State
  • @Environment
  • @StateObject
  • @ObservedObject
  • @EnvironmentObject

View 和 Dependence 之间的联系

Dependence graph

不是树状的而是相互关联的图形关系,通过图形关系 swiftUI 能够更高效的去比对值类型的 View 然后去更新需要更新的 View。

Identifier stability

从上面的内容可以了解到一个稳定的 identify 可以带来的是:

  • 直接影响到 lifetime
  • 优化性能
  • 减少 dependence 的变动
  • 避免状态 State 的丢失

因此在实践中需要注意的情况:

  • Explicit identify
    • 避免使用 uuid 这种 identify 在 list 中一旦变更全部 item 全部更新
    • 避免是用 slice 这种以顺序为 identify,当插入 item 不是在底部时,swiftUI 会处理插入到最后一个。
    • 避免使用可能重复的 identify 可能导致不更新。
  • Structural identify
    • 相同的View避免使用没必要的分支,会导致 identify 的丢失。
    • 尽量使用 inner modified(.opacity(show ? 1:0))

总结

SwiftUI 通过 Explicit identify 和 Structural identify 来确定唯一性,通过 identify 来控制 view 的生命周期,然后利用图形关系的依赖关系更高效的刷新视图。因此在 SwiftUI 中保证性能的最重要的一点就是保证 identify 的稳定性。

🔙  DailyApod
Xcode 项目多环境配置  🔜